<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <meta http-equiv="X-UA-Compatible" content="IE=edge" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>props的简写方式</title>
    </head>
    <body>
        <!-- 准备好DOM容器 -->
        <div id="test1"></div>
        <div id="test2"></div>
        <div id="test3"></div>

        <!-- 必须按照顺序引入JS -->
        <!-- 引入React核心库 -->
        <script src="../js/react.development.js"></script>
        <!-- 引入react-dom库，用于操作DOM -->
        <script src="../js/react-dom.development.js"></script>
        <!-- 引入prop-types库，用于限制组件props -->
        <script src="../js/prop-types.js"></script>
        <!-- 引入babel，用于将JSX翻译为JS -->
        <script src="../js/babel.min.js"></script>

        <!-- type必须为text/babel，代表里面的内容为JSX -->
        <script type="text/babel">
            // 创建组件
            class Person extends React.Component {
                // 对属性的限制，直接写在类里
                static propTypes = {
                    name: PropTypes.string.isRequired,
                    gender: PropTypes.string,
                    age: PropTypes.number,
                    // 指定speak属性接收函数，注意这里使用PropTypes.func
                    speak: PropTypes.func,
                };

                // 设置默认属性值，写在类里
                static defaultProps = {
                    gender: "不男不女",
                    age: 18,
                };

                /**
                 * 在 React 中，构造函数仅用于以下两种情况：
                 *   1. 通过给 this.state 赋值对象来初始化内部 state。
                 *   2. 为事件处理函数绑定实例在 constructor() 函数中不要调用 setState() 方法。如果你的组件需要使用内部 state，请直接在构造函数中为 this.state 赋值初始 state。只能在构造函数中直接为 this.state 赋值。如需在其他方法中赋值，你应使用 this.setState() 替代。
                 * 在 React 组件挂载之前，会调用它的构造函数。在为 React.Component 子类实现构造函数时，应在其他语句之前调用 super(props)。否则，this.props 在构造函数中可能会出现未定义的 bug。
                 */
                constructor(props) {
                    // 构造器是否接收props，是否传递给super，取决于是否希望在构造器中通过this访问props
                    super(props);

                    console.log("constructor", this.props);
                }

                render() {
                    // 注意：props是只读的
                    const { name, gender, age } = this.props;

                    return (
                        <ul>
                            <li>姓名：{name}</li>
                            <li>性别：{gender}</li>
                            <li>年龄：{age + 1}</li>
                        </ul>
                    );
                }
            }

            ReactDOM.render(
                <Person name="Tom" age={18} speak={speak} />,
                document.getElementById("test1")
            );
            ReactDOM.render(
                <Person name="Jerry" gender="女" />,
                document.getElementById("test2")
            );

            // 使用{...变量名}传递变量中的所有值到组件的props中
            // 原生JS不支持展示运算符展开对象，React+Babel支持在组件中使用展开运算符传递数据
            const p = { name: "老刘", gender: "女", age: 30 };
            ReactDOM.render(
                <Person {...p} />,
                document.getElementById("test3")
            );

            function speak() {
                console.log("我说话了");
            }
        </script>
    </body>
</html>
